use std::ops::Add;
use crypto::digest::Digest;
use crypto::ripemd160::Ripemd160;
use p256::pkcs8::der::Encode;
use sha2::{Digest as Digest2, Sha256};
use rust_base58::{FromBase58, ToBase58};

pub fn bytes_to_hex_string(bytes: &[u8]) -> String {
    let mut hex_str = String::new();
    for &byte in bytes {
        hex_str.push_str(&format!("{:02x}", byte));
    }
    hex_str
}

pub fn hex_string_to_bytes(s: &str) -> Vec<u8> {
    let mut b = vec![];
    for ch in s.chars() {
        if ch >= 'a' {
            b.push((ch as u8 - 'a' as u8) + 10);
        } else {
            b.push(ch as u8 - '0' as u8);
        }
    }
    b
}

pub fn ripemd160_hash(input: Vec<u8>) -> Vec<u8> {
    let mut hasher = Ripemd160::new();
    hasher.input(input.as_slice());
    let mut output: [u8; 20] = [0; 20];
    hasher.result(&mut output);
    Vec::from(output)
}

pub fn hash_pub_key(pub_key: &Vec<u8>) -> Vec<u8> {
    let mut hasher = Sha256::new();
    hasher.update(pub_key);
    let first_hash = hasher.finalize().to_vec();

    ripemd160_hash(first_hash)
}

pub fn base58encode(input: &Vec<u8>) -> String {
    input.to_base58()
}

pub fn base58decode(input: &str) -> Vec<u8> {
    input.as_bytes().from_base58().unwrap()
}

pub fn clear_key_raw_str(s: &String) -> String {
    let lines = s.split("\n");
    let mut r = String::new();
    for line in lines {
        if !line.starts_with("-----") {
            r.push_str(line.trim());
        }
    }

    r
}

pub fn push_key_label(key: &String, label: &str) -> String {
    const LINE_LEN: usize = 64;
    let mut r = String::new();
    r.push_str((String::from("-----BEGIN ") + label + " KEY-----\n").as_str());
    let mut count = 0;
    while count < key.len() {
        let mut end = count + LINE_LEN;
        if end > key.len() {
            end = key.len();
        }
        r.push_str(&*((&key[count..end]).to_string() + "\n"));
        count = end;
    }
    r.push_str((String::from("-----END ") + label + " KEY-----\n").as_str());

    r
}
